package com.topnav.mc.involve.http;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;

/**
 * 说明：摘要加密访问的http方法
 * @类名: DigestHttpUtils
 *
 * @author   kenny
 * @Date	 2020年4月13日下午6:50:17
 */
@Slf4j
public class DigestHttpUtils {


	/**
	 * 摘要认证 两次请求
	 *
	 * @param url
	 * @return 返回结果
	 */
	public static Boolean doPost(String url, String username, String password) {
	    log.debug("Post请求url:[{}]", url);
	    CloseableHttpClient httpClient = null;
	    CloseableHttpResponse response = null;
	    HttpPost httpPost = null;
	    String strResponse = null;
	    Boolean flag = false;

	    try {
	        httpClient = HttpClients.createDefault();
	        httpPost = new HttpPost(url);

	        // 构造请求头
	        httpPost.setHeader("Content-type", "application/json; charset=utf-8");
	        httpPost.addHeader("Cache-Control", "no-cache"); //设置缓存
	        httpPost.setHeader("Connection", "Close");

	        //设置超时时间
	        httpPost.setConfig(HttpUtil.createConfig(0));

	        // 执行请求
	        response = httpClient.execute(httpPost);
	        HttpEntity responseEntity = response.getEntity();

	        // 检验返回码
	        int statusCode = response.getStatusLine().getStatusCode();
	        log.debug("第一次发送摘要认证 Post请求 返回码:{}", statusCode);
	        if (401 == statusCode) {
	            strResponse = EntityUtils.toString(responseEntity, "utf-8");
	            log.debug("Post请求401返回结果:{}", strResponse);

	            // 组织参数，发起第二次请求
	            Header[] headers = response.getHeaders("WWW-Authenticate");
	            HeaderElement[] elements = headers[0].getElements();
	            String realm = null;
	            String qop = null;
	            String nonce = null;
	            String opaque = null;
	            String method = "POST";

	            String uri = url;//"/VIID/System/Register";

	            for (HeaderElement element : elements) {
	                if (element.getName().equals("X-Digest realm")) {
	                    realm = element.getValue();
	                } else if (element.getName().equals("qop")) {
	                    qop = element.getValue();
	                } else if (element.getName().equals("nonce")) {
	                    nonce = element.getValue();
	                } else if (element.getName().equals("opaque")) {
	                    opaque = element.getValue();
	                }
	            }
	            // 以上为 获取第一次请求后返回的 数据
	            String nc = "00000002";
	            String cnonce = "uniview";

	            // 后期变成可配置
	            String a1 = username + ":" + realm + ":" + password;
	            String a2 = method + ":" + uri;
	            String response1 = null;
	            // 获取 Digest 这个字符串
	            //String backString = response.getFirstHeader("WWW-Authenticate").getValue();
	            try {
	            	StringBuilder sb = new StringBuilder();
	            	sb.append(endCode(a1));
	            	sb.append(":");
	            	sb.append(nonce);
	            	sb.append(":");
	            	sb.append(nc);
	            	sb.append(":");
	            	sb.append(cnonce);
	            	sb.append(":");
	            	sb.append(qop);
	            	sb.append(":");
	            	sb.append(endCode(a2));
	            	response1 = endCode(sb.toString());
	            } catch (UnsupportedEncodingException e){
	                log.error("MD5异常:{}", e.getLocalizedMessage());
	            }
	            log.debug("backString: {}",response.getFirstHeader("WWW-Authenticate").getValue());
	            String authorization =  "X-Digest username=\"" +  username + "\""
	            		+ ",realm=\"" + realm + "\""
	            		+ ",nonce=\"" + nonce + "\""
	            		+ ",uri=\"" + uri + "\""
	            		+ ",response=\"" + response1+"\""
	            		+ ",opaque=\"" + opaque + "\""
	            		+ ",qop=" + qop
	            		+ ",nc=" + nc
	            		+ ",cnonce=" + "\"" + cnonce + "\"";

	            log.debug("Authorization: {}",authorization);
	            httpPost.addHeader("Authorization",authorization);
	            // 发送第二次请求
	            response = httpClient.execute(httpPost);
	            // 组织参数，发起第二次请求
/*	            Header[] headers1 = response.getHeaders("WWW-Authenticate");
	            HeaderElement[] elements1 = headers1[0].getElements();
	            log.debug("Authorization: {}",elements1);
*/
	            String cHASH = getHeaderValue(response,"C-HASH");
	            String sHASH = getHeaderValue(response,"S-HASH");
	            String xHASH = getHeaderValue(response,"X-HASH");


/*	            String cHASH = response.getHeaders("C-HASH");
	            String sHASH = null;
	            String xHASH = null;
	            for (HeaderElement element : elements1) {
	                if (element.getName().equals("C-HASH")) {
	                	cHASH = element.getValue();
	                } else if (element.getName().equals("S-HASH")) {
	                	sHASH = element.getValue();
	                } else if (element.getName().equals("X-HASH")) {
	                	xHASH = element.getValue();
	                }
	            }
	            */
	            log.debug("C-HASH: {}",cHASH);
	            log.debug("S-HASH: {}",sHASH);
	            log.debug("X-HASH: {}",xHASH);

	            HttpEntity entity = response.getEntity();
	            int statusCode1 = response.getStatusLine().getStatusCode();

	            log.debug("第二次发送摘要认证 Post请求 返回码:{}",statusCode1);
	            log.debug("HttpEntity: {}",entity);

	            if (HttpStatus.SC_OK == statusCode1) {
	                strResponse = EntityUtils.toString(entity, StandardCharsets.UTF_8);
	                flag = true;
	                return flag;
	            } else {
	                strResponse = EntityUtils.toString(entity, StandardCharsets.UTF_8);
	                log.error("第二次鉴权认证请求非 200 返回结果:{}", strResponse);
	                return flag;
	            }
	        } else {
	            strResponse = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
	            log.error("第一次鉴权认证请求非401 返回结果:{}", strResponse);
	        }
	    } catch (Exception e) {
	        log.error("摘要认证 发送请求失败", e.getLocalizedMessage());
	    } finally {
	        if (null != httpPost) {
	            httpPost.releaseConnection();
	        }
	        if (null != response) {
	            try {
	                response.close();
	            } catch (IOException e) {
	                log.error("httpResponse流关闭异常：", e);
	            }
	        }
	        if (null != httpClient) {
	            try {
	                httpClient.close();
	            } catch (IOException e) {
	                log.error("httpClient 流关闭异常：", e);
	            }
	        }
	    }
	    return flag;
	}

	private static String endCode(String data) throws UnsupportedEncodingException{
		return DigestUtils.md5Hex(data.getBytes("UTF-8"));
	}

	private static String getHeaderValue(HttpResponse response,String name){
		Header[] headers = response.getHeaders(name);
		if (headers != null && headers.length>0){
			HeaderElement[] elements = headers[0].getElements();
			for (HeaderElement element : elements) {
				return element.getName();
/*                if (element.getName().equals(name)) {
                	return element.getValue();
                }
*/            }
		}
		return null;
	}
}
